package bwmorg.bouncycastle.util;

import bigjava.math.BigInteger;
import bigjava.security.SecureRandom;

/**
 * BigInteger utilities.
 */
public final class BigIntegers
{
    private static final int        MAX_ITERATIONS = 1000;
    private static final BigInteger ZERO           = BigInteger.valueOf( 0 );

    /**
     * Return the passed in value as an unsigned byte array.
     * 
     * @param value value to be converted.
     * @return a byte array without a leading zero byte if present in the signed encoding.
     */
    public static byte[] asUnsignedByteArray( BigInteger value )
    {
        byte[] bytes = value.toByteArray();

        if( bytes[0] == 0 )
        {
            byte[] tmp = new byte[bytes.length - 1];

            System.arraycopy( bytes, 1, tmp, 0, tmp.length );

            return tmp;
        }

        return bytes;
    }

    /**
     * Return a random BigInteger not less than 'min' and not greater than 'max'
     * 
     * @param min the least value that may be generated
     * @param max the greatest value that may be generated
     * @param random the source of randomness
     * @return a random BigInteger value in the range [min,max]
     */
    public static BigInteger createRandomInRange( BigInteger min, BigInteger max, SecureRandom random )
    {
        int cmp = min.compareTo( max );
        if( cmp >= 0 )
        {
            if( cmp > 0 )
            {
                throw new IllegalArgumentException( "'min' may not be greater than 'max'" );
            }

            return min;
        }

        if( min.bitLength() > max.bitLength() / 2 )
        {
            return createRandomInRange( ZERO, max.subtract( min ), random ).add( min );
        }

        for( int i = 0; i < MAX_ITERATIONS; ++i )
        {
            BigInteger x = new BigInteger( max.bitLength(), random );
            if( x.compareTo( min ) >= 0 && x.compareTo( max ) <= 0 )
            {
                return x;
            }
        }

        // fall back to a faster (restricted) method
        return new BigInteger( max.subtract( min ).bitLength() - 1, random ).add( min );
    }
}
